package com.wksc.framework.impexp.thread;

import com.wksc.framework.impexp.bean.ImportExport;
import com.wksc.framework.impexp.constants.IEConstants;
import com.wksc.framework.impexp.constants.TaskStat;
import com.wksc.framework.impexp.constants.TaskType;
import com.wksc.framework.impexp.log.ImpExpLog;
import com.wksc.framework.impexp.task.ExpTask;
import com.wksc.framework.impexp.task.ImpTask;
import com.wksc.framework.impexp.task.Task;
import com.wksc.framework.impexp.template.BaseTemplate;
import com.wksc.framework.impexp.template.ExpTemplate;
import com.wksc.framework.impexp.template.ImpTemplate;
import com.wksc.framework.impexp.util.ClassFactory;

import java.io.InputStream;
import java.io.ObjectInputStream;
import java.sql.Blob;
import java.util.List;

/**
 * <p>
 * Title(文件名): TaskReload.java
 * </p>
 * <p>
 * Description(描述): 服务器重启后用于重新加载任务的类
 * </p>
 * <p>
 * Copyright(版权): Copyright (c) 2011
 * </p>
 * <p>
 * Company(公司): 成都四方信息技术有限公司
 * </p>
 * <p>
 * CreateTime(生成日期)：2011-12-2下午02:50:31
 * </p>
 *
 * @author wanglei
 * @version impExp_C13
 */
public class TaskReload implements Runnable {
    /**
     * @Fields LOG : 记录日志用
     */
    private static final ImpExpLog LOG = ClassFactory.getLog(TaskReload.class);
    /**
     * @Fields sleepIntervalMax : 最大休眠时间
     * @Fields sleepIntervalUsual : 正常休眠时间
     */
    private final long sleepIntervalMax = 30000, sleepIntervalUsual = 3000;
    /**
     * @Fields sleepInterval : 暂停时间
     */
    private long sleepInterval = sleepIntervalUsual; // 触发addtorun事件,默认3s一次

    @Override
    public void run() {
        //将所有30s内没有更新标志的任务全部更新为1(等待)
        //无论是更新失败还是成功都应该继续王霞执行,但是后面文件加载上会有冲突
        //本机取消的时候挂掉,重启后将本机取消任务置为异常
        int updateCnt = ClassFactory.getImpExpDao().resetTaskWaiting(); //将2改为1,用于判断后面执行中任务数量
        if (updateCnt < 0) {
            LOG.info("Change no running task to waiting");
        } else {
            LOG.info("Change " + updateCnt + " running task to waiting");
        }
        //		if (updateCnt > 0) {
        //			LOG.info("Change " + updateCnt + " running task to waiting");
        //		} else { //数据库异常时,这个地方会打印-1,所以使用if else
        //			LOG.info("Change 0 running task to waiting");
        //		}
        //数据库中查找有无待恢复的任务
        List<?> tasks = ClassFactory.getImpExpDao().findReload();
        List<?> pausedTasks = ClassFactory.getImpExpDao().findPausedTasks(true,
                false);

        LOG.info("************ Import ReloadJobs Start ************");
        //恢复之前正在运行与等待的任务
        reloadRunningTasks(tasks, true);
        //恢复之前暂停的任务
        reloadPausedTasks(pausedTasks);
        LOG.info("************ Import ReloadJobs End ************");

        while (true) {
            try { //测试的时候发现这个地方抛出锁操作异常,导致重试失效
                this.searchWaiting();
            } catch (Exception e) {
                sleepInterval = sleepIntervalMax;
                LOG.error(e.getMessage(), e);
            }
            //			this.updateRefreshDate(); //这个循环的功能不单纯,不适合用来做心跳
            try {
                Thread.sleep(sleepInterval);
            } catch (InterruptedException e) {
                LOG.error("reload interrupted", e);
            }
        }
    }

    private void updateRefreshDate() {
        try {
            TaskManage.writeLock.lock();
            //			TaskManage.updateRefreshDate(); //任务超时
            // 主机超时
            //			ClassFactory.getImpExpDao().refreshHeartBeat();
        } finally {
            TaskManage.writeLock.unlock();
        }
    }

    /**
     * 功能描述: checkeStyle
     *
     * @Title: searchWaiting
     * @Description: 查找其他机器处理不过来的任务(状态1, 8), 将其处理标识改为本机处理
     * @creator Owner
     */
    private void searchWaiting() {
        //		try {
        //去掉这个地方的锁,原因为:
        //1.对这个方法的调用入口只有一个地方,单线程,不需要枷锁
        //2.测试的时候发现有时候会报错解锁冲突,抛出异常导致while循环终止
        //			TaskManage.writeLock.lock();
        if (TaskManage.getWaitingNum() > 0 || TaskManage.getRunningNum() > 0) { //如果有运行中和等待中的任务
            return; //这个地方一定不能做任何会触发addToRun的操作,否则会造成并行执行
        }
        //处理其他机器处理不过来的任务,更新1,8的任务的处理者为本机
        if (ClassFactory.getImpExpDao().updateClusterMarkOfWaitingTasks() < 1) { //如果没有更新到数据,return
            //a,b集群,由于a暂停的任务被b恢复,导致a的暂停队列无法清空,这个问题
            sleepInterval = sleepIntervalMax; //下一次轮询时间改为30s
            return;
        }
        sleepInterval = sleepIntervalUsual; //下一次轮询时间改为3s

        List<?> reloadTasks = ClassFactory.getImpExpDao().findReload(); //重新加载1,8 (2可以不用重新加载)
        reloadRunningTasks(reloadTasks, false);
        //同步一下暂停队列
        List<?> pausedTasks = ClassFactory.getImpExpDao().findPausedTasks(true,
                false); //加载到本机
        TaskManage.synchronizePauseList(pausedTasks);
    }

    /**
     * 功能描述: checkeStyle
     *
     * @param tasks 任务列表
     * @Title: reloadRunningTasks
     * @Description: 加载任务:等待,重新加载
     * @creator Owner
     */
    public static void reloadRunningTasks(List<?> tasks, boolean setStateReload) {
        Task task = null;
        if (null == tasks || tasks.isEmpty()) {
            return;
        }

        for (Object obj : tasks) {
            task = recoverTask(obj); //任务恢复到内存
            //			if (task != null) { //测试的时候发现,a加载b的任务,但是a上面没有b的文件,这个时候,读取importStream
            TaskManage.addToRun(task); //任务加载到内存和数据库
            //			}
        }
        if (setStateReload) {
            task.setTaskStat(TaskStat.TASK_RELOADED);
        }
    }

    /**
     * 功能描述: checkeStyle
     *
     * @param pausedTasks 暂停任务列表
     * @Title: reloadPausedTasks
     * @Description: 加载暂停任务
     * @creator Owner
     */
    public static void reloadPausedTasks(List<?> pausedTasks) {
        Task task = null;
        if (null == pausedTasks || pausedTasks.isEmpty()) {
            return;
        }

        for (Object obj : pausedTasks) {
            task = recoverTask(obj);
            TaskManage.addToPause(task);
        }
    }

    /**
     * 功能描述: checkeStyle
     *
     * @param obj obj
     * @return Task 返回类型
     * @Title: recoverTask
     * @Description: TODO(这里用一句话描述这个方法的作用)
     * @creator Owner
     */
    private static Task recoverTask(Object obj) {
        Task task = null;
        ImportExport ie = (ImportExport) obj;
        if (ie.getJobtype() != 3) {
            deleltFile(ie.getFilename());
        }
        Blob template = ie.getJobtemplate();
        try {
            InputStream inputStream = template.getBinaryStream();
            ObjectInputStream objectInputStream = new ObjectInputStream(
                    inputStream);
            BaseTemplate bt = (BaseTemplate) objectInputStream.readObject();
            if (TaskType.EXP_TASK == bt.getTaskType()) {
                task = new ExpTask((ExpTemplate) bt);
            } else {
                task = new ImpTask((ImpTemplate) bt);
            }
        } catch (Exception e) {
            LOG.error("import/export reload task occur error", e);
        }
        return task;
    }

    /**
     * MethodDesc: 删除服务器重启前，任务模版可能会产生的临时文件
     *
     * @param fileName fileName
     * @author QinJinxue
     */
    private static void deleltFile(String fileName) {
        String filePath = IEConstants.TEM_PATH + IEConstants.SEPARATOR
                + fileName;
        //FileTools.delFileFolder(filePath + ".csv");
        //FileTools.delFileFolder(filePath + ".xls");
        //FileTools.delFileFolder(filePath + ".zip");
        //FileTools.delFileFolder(filePath);
        filePath = IEConstants.EXP_PATH + IEConstants.SEPARATOR + fileName;
        //FileTools.delFileFolder(filePath + ".csv");
        //FileTools.delFileFolder(filePath + ".xls");
        //FileTools.delFileFolder(filePath + ".zip");
    }
}
